Skip to main content

Integration & Implementation

1. Sample API Implementations

1.1 Node.js/Express Implementation

const express = require('express');
const app = express();

app.use(express.json());

// Middleware for authentication
const authenticate = (req, res, next) => {
const clientId = req.headers['clientid'];
const authHeader = req.headers['authorization'];

if (!clientId || !authHeader) {
return res.status(401).json({
statusCode: 'ERROR_INVALID_CLIENT_ID',
statusMessage: 'Missing authentication credentials'
});
}

// Validate Basic Auth
const base64Credentials = authHeader.split(' ')[1];
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
const [clientIdFromAuth, clientSecret] = credentials.split(':');

// Validate credentials against your stored values
if (!validateCredentials(clientIdFromAuth, clientSecret)) {
return res.status(401).json({
statusCode: 'ERROR_INVALID_CLIENT_ID',
statusMessage: 'Invalid client credentials'
});
}

next();
};

// GET RISK PROFILE API
app.post('/v1/banking-activity', authenticate, async (req, res) => {
// Check for risk-profile=true query parameter
if (req.query['risk-profile'] !== 'true') {
return res.status(400).json({
statusCode: 'ERROR_INVALID_MSG',
statusMessage: 'Missing risk-profile=true query parameter'
});
}
const transactionId = req.headers['transactionid'];

try {
const bankingActivity = req.body;

// Validate required fields
if (!bankingActivity.activityId || !bankingActivity.userContext) {
return res.status(400)
.header('TransactionId', transactionId)
.json({
activityId: bankingActivity.activityId,
statusCode: 'ERROR_INVALID_MSG',
statusMessage: 'Missing required fields'
});
}

// Calculate risk profile using your anomaly detection engine
const riskProfile = await calculateRiskProfile(bankingActivity);

res.status(200)
.header('TransactionId', transactionId)
.json(riskProfile);

} catch (error) {
res.status(500)
.header('TransactionId', transactionId)
.json({
statusCode: 'ERROR_INTERNAL_SERVER',
statusMessage: 'Internal server error'
});
}
});

// CREATE BANKING ACTIVITIES API (Bulk)
app.post('/v1/banking-activities', authenticate, async (req, res) => {
const transactionId = req.headers['transactionid'];

try {
const { bankingActivities } = req.body;

// Process each activity and store in database
const riskProfiles = await Promise.all(
bankingActivities.map(activity => processActivity(activity))
);

res.status(200)
.header('TransactionId', transactionId)
.json({ riskProfiles });

} catch (error) {
res.status(500)
.header('TransactionId', transactionId)
.json({
statusCode: 'ERROR_INTERNAL_SERVER',
statusMessage: 'Internal server error'
});
}
});

// DELETE USER BANKING ACTIVITIES API
app.delete('/v1/banking-activities', authenticate, async (req, res) => {
const transactionId = req.headers['transactionid'];
const { institutionid, userid, loginname } = req.query;

try {
if (!institutionid) {
return res.status(400)
.header('TransactionId', transactionId)
.json({
statusCode: 'ERROR_INVALID_MSG',
statusMessage: 'institutionid is required'
});
}

if (!userid && !loginname) {
return res.status(400)
.header('TransactionId', transactionId)
.json({
statusCode: 'ERROR_INVALID_MSG',
statusMessage: 'Either userid or loginname is required'
});
}

// Delete user data from your database
const deleted = await deleteUserData(institutionid, userid, loginname);

if (!deleted) {
return res.status(400)
.header('TransactionId', transactionId)
.json({
statusCode: userid ? 'ERROR_INVALID_USER_ID' : 'ERROR_INVALID_LOGIN_NAME',
statusMessage: userid ? 'Invalid User Id' : 'Invalid Login Name'
});
}

res.status(200)
.header('TransactionId', transactionId)
.json({ statusCode: 'SUCCESS' });

} catch (error) {
res.status(500)
.header('TransactionId', transactionId)
.json({
statusCode: 'ERROR_INTERNAL_SERVER',
statusMessage: 'Internal server error'
});
}
});

// Risk calculation function (implement your anomaly detection logic)
async function calculateRiskProfile(activity) {
// Your anomaly detection engine logic here
return {
activityId: activity.activityId,
statusCode: 'SUCCESS',
riskScore: 25.0,
riskLevel: 'Low',
riskAdvice: 'Allow',
riskFactors: []
};
}

app.listen(3000, () => {
console.log('Anomaly Detection API listening on port 3000');
});

1.2 Python/Flask Implementation

from flask import Flask, request, jsonify
import base64
from functools import wraps

app = Flask(__name__)

def authenticate(f):
@wraps(f)
def decorated(*args, **kwargs):
client_id = request.headers.get('ClientId')
auth_header = request.headers.get('Authorization')

if not client_id or not auth_header:
return jsonify({
'statusCode': 'ERROR_INVALID_CLIENT_ID',
'statusMessage': 'Missing authentication credentials'
}), 401

# Validate Basic Auth
try:
auth_type, credentials = auth_header.split(' ')
decoded = base64.b64decode(credentials).decode('utf-8')
client_id_auth, client_secret = decoded.split(':')

if not validate_credentials(client_id_auth, client_secret):
raise ValueError('Invalid credentials')
except:
return jsonify({
'statusCode': 'ERROR_INVALID_CLIENT_ID',
'statusMessage': 'Invalid client credentials'
}), 401

return f(*args, **kwargs)
return decorated


@app.route('/v1/banking-activity', methods=['POST'])
@authenticate
def get_risk_profile():
transaction_id = request.headers.get('TransactionId')

# Check for risk-profile=true query parameter
if request.args.get('risk-profile') != 'true':
response = jsonify({
'statusCode': 'ERROR_INVALID_MSG',
'statusMessage': 'Missing risk-profile=true query parameter'
})
response.headers['TransactionId'] = transaction_id
return response, 400

try:
activity = request.json

# Validate required fields
if not activity.get('activityId') or not activity.get('userContext'):
response = jsonify({
'activityId': activity.get('activityId'),
'statusCode': 'ERROR_INVALID_MSG',
'statusMessage': 'Missing required fields'
})
response.headers['TransactionId'] = transaction_id
return response, 400

# Calculate risk profile
risk_profile = calculate_risk_profile(activity)

response = jsonify(risk_profile)
response.headers['TransactionId'] = transaction_id
return response, 200

except Exception as e:
response = jsonify({
'statusCode': 'ERROR_INTERNAL_SERVER',
'statusMessage': str(e)
})
response.headers['TransactionId'] = transaction_id
return response, 500


@app.route('/v1/banking-activities', methods=['POST'])
@authenticate
def create_banking_activities():
transaction_id = request.headers.get('TransactionId')

try:
data = request.json
activities = data.get('bankingActivities', [])

risk_profiles = [process_activity(a) for a in activities]

response = jsonify({'riskProfiles': risk_profiles})
response.headers['TransactionId'] = transaction_id
return response, 200

except Exception as e:
response = jsonify({
'statusCode': 'ERROR_INTERNAL_SERVER',
'statusMessage': str(e)
})
response.headers['TransactionId'] = transaction_id
return response, 500


@app.route('/v1/banking-activities', methods=['DELETE'])
@authenticate
def delete_user_activities():
transaction_id = request.headers.get('TransactionId')
institution_id = request.args.get('institutionid')
user_id = request.args.get('userid')
login_name = request.args.get('loginname')

try:
if not institution_id:
response = jsonify({
'statusCode': 'ERROR_INVALID_MSG',
'statusMessage': 'institutionid is required'
})
response.headers['TransactionId'] = transaction_id
return response, 400

if not user_id and not login_name:
response = jsonify({
'statusCode': 'ERROR_INVALID_MSG',
'statusMessage': 'Either userid or loginname is required'
})
response.headers['TransactionId'] = transaction_id
return response, 400

# Delete user data
deleted = delete_user_data(institution_id, user_id, login_name)

if not deleted:
error_code = 'ERROR_INVALID_USER_ID' if user_id else 'ERROR_INVALID_LOGIN_NAME'
response = jsonify({
'statusCode': error_code,
'statusMessage': 'Invalid User Id' if user_id else 'Invalid Login Name'
})
response.headers['TransactionId'] = transaction_id
return response, 400

response = jsonify({'statusCode': 'SUCCESS'})
response.headers['TransactionId'] = transaction_id
return response, 200

except Exception as e:
response = jsonify({
'statusCode': 'ERROR_INTERNAL_SERVER',
'statusMessage': str(e)
})
response.headers['TransactionId'] = transaction_id
return response, 500


def calculate_risk_profile(activity):
"""Implement your anomaly detection logic here."""
return {
'activityId': activity['activityId'],
'statusCode': 'SUCCESS',
'riskScore': 25.0,
'riskLevel': 'Low',
'riskAdvice': 'Allow',
'riskFactors': []
}


if __name__ == '__main__':
app.run(port=3000, ssl_context='adhoc') # Use proper SSL in production

2. Testing and Certification

2.1 Integration Testing

Before going live, you must complete integration testing with Candescent:

  1. API Endpoint Verification - All three APIs respond correctly
  2. Authentication Testing - Credentials validation works properly
  3. Error Handling - Appropriate error codes returned for various scenarios
  4. Performance Testing - Response times meet requirements
  5. Load Testing - Service handles expected transaction volumes

2.2 Test Scenarios

Your implementation should handle these test scenarios:

ScenarioExpected Response
Valid login activitySUCCESS with risk profile
Invalid institution IDERROR_INVALID_CLIENT_ID
Missing required fieldsERROR_INVALID_MSG
Invalid transaction ID headerERROR_INVALID_TRANSACTION_ID
Bulk activities (10+ items)SUCCESS for each activity
Delete with valid user IDSUCCESS
Delete with invalid user IDERROR_INVALID_USER_ID

2.3 Historical Data Loading

Before production enablement:

  1. Coordinate with Candescent for historical data transfer schedule
  2. Prepare your system to receive bulk data via createBankingActivities API
  3. Verify 90 days of historical data is loaded per Financial Institution
  4. Confirm risk models are updated with historical data

This document is confidential and proprietary. The information contained herein may not be copied, reproduced, transmitted, or used without the express written consent of Candescent Corporation.